package com.xiaoluyy.demo.biz.test;

import com.xiaoluyy.demo.config.MybatisConfig;
import com.xiaoluyy.demo.config.PropertiesConfig;
//import com.xiaoluyy.demo.config.ThriftClientConfig;
import com.xiaoluyy.demo.config.ThriftServiceConfig;
import org.junit.runner.RunWith;
import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.AopProxy;
import org.springframework.aop.support.AopUtils;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;

import java.lang.reflect.Field;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class,
        classes = {MybatisConfig.class,ThriftServiceConfig.class,/*ThriftClientConfig.class,*/PropertiesConfig.class})
public class BizTestBase {

    public static void injectMockObject(Object host, String fieldname, Object mockObject){
        try{
            Field f = getTarget(host).getClass().getDeclaredField(fieldname);
            f.setAccessible(true);
            f.set(host, mockObject);
            f.setAccessible(false);
        }catch(Exception e){
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取 目标对象
     * @param proxy 代理对象
     * @return
     * @throws Exception
     */
    private static Object getTarget(Object proxy) throws Exception {
                 if(!AopUtils.isAopProxy(proxy)) {
                         return proxy;//不是代理对象
                     }
                 if(AopUtils.isJdkDynamicProxy(proxy)) {
                         return getJdkDynamicProxyTargetObject(proxy);
                     } else { //cglib
                         return getCglibProxyTargetObject(proxy);
                     }
            }

    private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
                 Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
                 h.setAccessible(true);
                 Object dynamicAdvisedInterceptor = h.get(proxy);
                 Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
                 advised.setAccessible(true);
                 Object target = ((AdvisedSupport)advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
                 return target;
             }


    private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
                 Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
                 h.setAccessible(true);
                 AopProxy aopProxy = (AopProxy) h.get(proxy);
                 Field advised = aopProxy.getClass().getDeclaredField("advised");
                 advised.setAccessible(true);
                 Object target = ((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget();
                 return target;
             }

}
